Skip to content

feat: add BugDrop Sandbox#154

Open
neonwatty wants to merge 3 commits into
mainfrom
feat/widget-sandbox
Open

feat: add BugDrop Sandbox#154
neonwatty wants to merge 3 commits into
mainfrom
feat/widget-sandbox

Conversation

@neonwatty
Copy link
Copy Markdown
Collaborator

Summary

  • add a hosted BugDrop Sandbox for configuring, previewing, and generating widget script tags
  • add sandbox preview routes, iframe isolation, repo validation, install-check handling, and copy failure state
  • document the sandbox and align data-welcome docs with runtime behavior
  • add local E2E coverage and preview/production asset smoke checks

Validation

  • npm run build:widget
  • npm run validate
  • npm run test:e2e -- --project=chromium e2e/sandbox.spec.ts
  • npm run test:e2e -- --project=chromium
  • Playwright desktop/mobile rendered smoke check of /sandbox/

Closes #151

neonwatty added 3 commits May 11, 2026 09:26
Apply review findings on PR #154:

- ci-testing.mdx welcome-screen test: tag welcome modal with `bd-welcome`
  class so the published example can distinguish it from the feedback form
- CI/deploy smoke checks: replace `curl -sfo /dev/null` (passes on any 200)
  with content-grep assertions; move worker origin to `env:` block
- checkInstallation: bind and console.warn the error, distinguish HTTP
  errors from network errors instead of showing a generic "unable to reach"
- Sanitizer feedback: aggregate rejected fields in updatePreview and
  surface "Ignored invalid values for: ..." inline below the preview
- Redaction copy: mention auto-masked password/cc-* defaults
- Extract SCRIPT_ATTRIBUTE_MAP to public/sandbox/attribute-map.js as ESM
  module imported by sandbox.js; preview.html keeps an inlined copy
  because the iframe sandbox="allow-scripts" (no allow-same-origin)
  blocks ES module imports via CORS
- src/index.ts: delete 5 redundant `app.get('/sandbox/...')` handlers
  and `fetchAsset` helper; Wrangler Assets serves them directly so the
  worker is no longer invoked (and logger no longer runs) for every
  static asset hit. Keep only the /sandbox -> /sandbox/ 301 redirect
- preview.html: add script.onerror banner when /widget.js fails to load
- Extract sanitizers to public/sandbox/sanitizers.js (45-test vitest
  suite covers escapeAttribute ordering, sanitizeIcon javascript:/data:
  rejection, sanitizeCategoryLabels JSON shape/size, sanitizeCssToken
  XSS chars + embedded whitespace, isValidRepo length boundaries, etc.)
- Tighten sanitizeCategoryLabels to require non-null non-array object
- Tighten sanitizeCssToken to reject embedded \r\n\t
- copyScript: bind and console.warn the clipboard error
- sandbox.css: drop color-scheme: light -> light dark
- E2E: replace waitForTimeout(300) with deterministic releaseSlow +
  expect.poll; add stale-check-on-input-change test (covers the
  readConfig().repo !== repo guard at the second site); add
  sanitize-feedback visibility test; assert content-type on each
  served asset (catches 200-with-wrong-content)
Address findings from re-running the pr-review-toolkit on the prior fix
commit:

- sanitizeIcon: reject URLs with embedded credentials (user:pass@host)
  to prevent credential leak into data-icon attribute
- sanitizeCategoryLabels: reject __proto__/constructor/prototype keys
  to harden against prototype-pollution-style payloads
- checkInstallation: catch JSON parse failures separately so a 200 OK
  with HTML body surfaces as "HTTP 200: invalid JSON response" rather
  than the generic network-error message
- readConfig: console.warn when an ATTRIBUTE_MAP key has no matching
  form field (surface HTML/map drift instead of silently sending '')
- FIELD_LABELS: comment explaining that new sanitized fields must be
  added here to surface in the rejection notice
- preview.html: add window.error listener to catch widget bundle
  runtime errors (script.onerror only covers load failures), share
  the banner across both paths via a one-shot showBanner helper
- preview.html: tighten the duplication comment to be precise about
  opaque-origin treatment and missing CORS headers on Workers Assets
- ci-testing.mdx: name the bugdrop_welcomed_* localStorage prefix so
  the documented test caveat is actionable
- ci.yml/deploy.yml: add a sanitizers.js content-grep check and
  replace the ambiguous 'BugDrop Sandbox' substring (which also matches
  'BugDrop Sandbox Preview') with the index-specific id="sandbox-form"
- e2e mid-flight race test: await page.waitForResponse for the slow
  route after releasing it so the negative-match assertion actually
  verifies the stale-discard guard fires (rather than passing trivially)
- e2e: new HTTP 500 test asserting the bound error surfaces in the UI
- e2e: new malformed-JSON test for the new parse-error branch
- e2e: new test routing widget.js to 404 to verify the preview banner
- e2e (widget.spec.ts): assert .bd-welcome class on the welcome modal
  so the ci-testing.mdx docs example can't silently regress
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build a BugDrop Lab for widget setup and screenshot/redaction testing

1 participant